# coding=utf-8
from __future__ import print_function, absolute_import
from gm.api import *

from manager import BarManager

'''
普吸金缠论策略示例1
仅作为技术演示，不可直接实盘使用。
缠论分析技术需要灵活运用，本示例仅演示如何调用缠论分析函数，如何取分析返回结果，完全没有考虑策略的收益。
实用的策略，比如见到什么样的买点买入，在什么情况下卖出，需要自己精心设计。

本策略基于5分钟级别数据，多空双向操作，“买卖点+分型停顿”买入，“买卖点+分型”或“止损”卖出。
普吸金缠论有5种分析方法，本示例没有进行配置，使用默认的方法0。
与普吸金缠论相关的所有内容可参考《普吸金缠论大全》。
与本示例相关的所有资料和工具都可到QQ群881645236中下载。
后续我们将推出更加实用的策略，还会推出使用C++的策略。
'''

def init(context):
    context.symbol = 'CFFEX.IC2301'                     # 交易标的

    # 创建一个K线管理器
    context.manager: BarManager = BarManager()

    context.position = 0                                # 仓位
    context.cancel_price = 0.0                          # 止损价

    subscribe(context.symbol, '300s', count=1)          # 订阅行情

    
def on_bar(context, bars):
    # 对接收到的每根K线进行操作
    for bar in bars:
        # 更新数据并进行缠论计算
        context.manager.update_bar(bar)
        if context.manager.errNo.value != 0:
            # 如果缠论计算失败，不继续操作
            # 注：缠论计算需要一定数据量，所以回测开始的一段时间不会有操作
            continue

        # 如果当前空仓
        if context.position == 0:
            # 取缠论开仓信息
            ret, cancel_price = context.manager.is_buy_point()
            if ret != 0:
                # 如果有买点
                print('{}: 标的：{}，买卖点：{}'.format(context.now, context.symbol, ret))

            if ret < 0:
                # 开多仓
                order_volume(symbol=context.symbol, volume=1, side=OrderSide_Buy, position_effect=PositionEffect_Open,
                            order_type=OrderType_Market)
                print('{}:标的：{}，操作：开多仓，委托价格：{}，委托数量：{}'.format(context.now, context.symbol, bar.close, 1))
                context.position = 1
                context.cancel_price = cancel_price
            elif ret > 0:
                # 开空仓
                order_volume(symbol=context.symbol, volume=1, side=OrderSide_Sell, position_effect=PositionEffect_Open,
                            order_type=OrderType_Market)
                print('{}:标的：{}，操作：开空仓，委托价格：{}，委托数量：{}'.format(context.now, context.symbol, bar.close, 1))
                context.position = -1
                context.cancel_price = cancel_price

        # 如果已经有多仓
        elif context.position > 0:
            op_flag = False     # 是否平仓标志
            if bar.close < context.cancel_price:
                # 破止损价平仓
                op_flag = True
            else:
                # 平仓点平仓
                ret = context.manager.is_sell_point()
                if ret > 0:
                    op_flag = True

            if op_flag:
                # 以市价平多仓
                order_volume(symbol=context.symbol, volume=1, side=OrderSide_Sell, position_effect=PositionEffect_Close,
                            order_type=OrderType_Market)
                print('{}:标的：{}，操作：平多仓，委托价格：{}，委托数量：{}'.format(context.now, context.symbol, bar.close, 1))
                context.position = 0

        # 如果已经有空仓
        elif context.position < 0:
            op_flag = False     # 是否平仓标志
            if bar.close > context.cancel_price:
                # 破止损价平仓
                op_flag = True
            else:
                # 平仓点平仓
                ret = context.manager.is_sell_point()
                if ret < 0:
                    op_flag = True

            if op_flag:
                # 以市价平空仓
                order_volume(symbol=context.symbol, volume=1, side=OrderSide_Buy,
                            position_effect=PositionEffect_Close, order_type=OrderType_Market)
                print('{}:标的：{}，操作：平空仓，委托价格：{}，委托数量：{}'.format(context.now, context.symbol, bar.close, 1))
                context.position = 0


def on_backtest_finished(context, indicator):
    print('*'*50)
    print('回测已完成，请通过右上角“回测历史”功能查询详情。')
    

if __name__ == '__main__':
    '''
        strategy_id策略ID,由系统生成
        filename文件名,请与本文件名保持一致
        mode实时模式:MODE_LIVE回测模式:MODE_BACKTEST
        token绑定计算机的ID,可在系统设置-密钥管理中生成
        backtest_start_time回测开始时间
        backtest_end_time回测结束时间
        backtest_adjust股票复权方式不复权:ADJUST_NONE前复权:ADJUST_PREV后复权:ADJUST_POST
        backtest_initial_cash回测初始资金
        backtest_commission_ratio回测佣金比例
        backtest_slippage_ratio回测滑点比例
    '''
    run(strategy_id='d8a5c590-94cb-11ed-9990-54ee75a30838',
        filename='main.py',
        mode=MODE_BACKTEST,
        token='f01adc1f8a69fbc48d5675edb0a99b7486359bfd',
        backtest_start_time='2022-10-26 09:00:00',
        backtest_end_time='2023-01-18 15:00:00',
        backtest_adjust=ADJUST_PREV,
        backtest_initial_cash=1000000,
        backtest_commission_ratio=0.0001,
        backtest_slippage_ratio=0.0001)
